﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Oracle.DataAccess.Client;
using System.Data;
using System.Linq.Expressions;
using System.Reflection;

public partial class ExpressionTree表达式树_表达式树DataReader与自动生成 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        accc bbcc = new accc();

        var fieldtype = typeof(Nullable<int>);
        //var act = SetValueToEntity<accc>(0, "Abc", fieldtype, IsNullableType(fieldtype));
        Action<accc, int> aab = SetNullableValue<accc>();
        aab(bbcc, 123);

      //  string sql = "select * from INCOM_TERMINALFAULT t";
        string sql = "select *  from DAT_DATAWAREHOUSE t  where t.terminalcode=222  and rownum<14000";
        string condb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.79)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=nek)));Persist Security Info=True;User ID=incom; Password=intest;Pooling=true;Min Pool Size=1;Connection Lifetime=120;Connection Timeout=60;";

        //读取数据
        Action reader1 = () => 读取DataReader(sql,condb);
        //Action reader2 = () => { 读取DataReader手动代码(sql,condb); };
        Action reader3 = () => { GetDataTable(sql,condb); };

        long t1 = reader1.StopwatchRun();
        long t2 = 0;// reader2.StopwatchRun();
        long t3 = reader3.StopwatchRun();

        Response.Write(string.Join("<br/>", t1, t2, t3));
    }

    /// <summary>
    /// 字典缓存
    /// </summary>
    public static Dictionary<int, dynamic> dynamicClassToListCache = new Dictionary<int, dynamic>();

    public void 读取DataReader手动代码(string sql = "select * from INCOM_TERMINALFAULT t", string dbcon = null)
    {
        OracleConnection conn;
        IDataReader reader = GetReader(out conn, sql, dbcon);
        try
        {
            List<Tfault> list = new List<Tfault>();
            while (reader.Read())
            {

                Tfault fault = new Tfault()
                {
                    FAULTID = reader.IsDBNull(0) ? null : reader.GetString(0),
                    TERMINALCODE = reader.GetInt32(1),
                    MD5CODE = reader.IsDBNull(2) ? null : reader.GetString(2),
                    BATCHID = reader.IsDBNull(3) ? null : reader.GetString(3),
                    FAULTCODE = reader.IsDBNull(4) ? null : reader.GetString(4),
                    STARTTIME = reader.GetDateTime(5),
                    ENDTIME = reader.IsDBNull(6) ? null : new Nullable<System.DateTime>(reader.GetDateTime(6)),
                    NOTE = reader.IsDBNull(7) ? null : reader.GetString(7),
                    FLAG = reader.IsDBNull(8) ? null : new Nullable<System.Int16>(reader.GetInt16(8)),
                    CREATETIME = reader.IsDBNull(9) ? null : new Nullable<System.DateTime>(reader.GetDateTime(9)),
                    MAXBUGCODE = reader.IsDBNull(10) ? null : new Nullable<System.Double>(reader.GetDouble(10)),
                    FAULTCATEGORY = reader.GetString(11),
                    SPN = reader.IsDBNull(12) ? null : new Nullable<System.Int64>(reader.GetInt64(12)),
                    FMI = reader.IsDBNull(13) ? null : new Nullable<System.Int64>(reader.GetInt64(13)),
                    SA = reader.IsDBNull(14) ? null : new Nullable<System.Int64>(reader.GetInt64(14)),
                    SUGGESTION = reader.IsDBNull(15) ? null : reader.GetString(15),
                    CARID = reader.IsDBNull(16) ? null : new Nullable<System.Decimal>(reader.GetDecimal(16)),
                };
                list.Add(fault);
            }

        }
        finally
        {
            if (reader != null)
            {
                reader.Close();
                reader.Dispose();
            }
            conn.Close();
            conn.Dispose();
        }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <remarks>
    /// 步骤说明:
    ///1.读取DataReader
    ///2.读取表结构
    ///3.根据表结构生成实体类
    ///4.将生成的实体类进行关系处理,用表达式树生成
    ///5.填充生成实体类.输出
    /// </remarks>
    public void 读取DataReader(string sql = "select * from INCOM_TERMINALFAULT t", string dbcon = null)
    {
        //1.读取DataReader
        //2.读取表结构
        //3.根据表结构生成实体类
        //4.将生成的实体类进行关系处理,用表达式树生成
        //5.填充生成实体类.输出
        OracleConnection conn;
        IDataReader reader = GetReader(out conn, sql, dbcon);
        try
        {
            dynamic fun = null;
            //SQL识别码
            int hascodekey = sql.GetHashCode();
            //看看缓存是否存
            if (!dynamicClassToListCache.ContainsKey(hascodekey))
            {
                //获取 tb
                DataTable tb = reader.GetSchemaTable();
                var par = CreateCodes(tb);
                fun = par.Compile();
                dynamicClassToListCache.Add(hascodekey, fun);
            }
            else
            {
                fun = dynamicClassToListCache[hascodekey];
            }
            //产生一个自赋值处理器
            // var result=         SetValueToEntity<accc>(0, reader.GetName(0),  typeof(accc).GetProperty("TERMINALCODE").PropertyType ,true);
            var list = fun(reader);
        }
        finally
        {
            if (reader != null)
            {
                reader.Close();
                reader.Dispose();
            }
            conn.Close();
            conn.Dispose();
        }
    }




    #region 数据读取功能
    public System.Data.IDataReader GetReader(out OracleConnection conn, string sql = null,
        string condb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.79)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=ney)));Persist Security Info=True;User ID=platform; Password=intest;Pooling=true;Min Pool Size=1;Connection Lifetime=120;Connection Timeout=60;"
        )
    {
        OracleDataReader reader = null;

        //初始化联接字符串
        if (string.IsNullOrEmpty(condb))
        {
            condb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.79)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=ney)));Persist Security Info=True;User ID=platform; Password=intest;Pooling=true;Min Pool Size=1;Connection Lifetime=120;Connection Timeout=60;";
        }
        string query = string.IsNullOrEmpty(sql) ? "select *  from    Incom_terminal" : sql;


        //先查询,如果终端号不存在则添加
        conn = new OracleConnection(condb);

        OracleCommand cmd = conn.CreateCommand();
        cmd.CommandText = query;
        try
        {
            conn.Open();
            reader = cmd.ExecuteReader();
        }
        catch (OracleException ex)
        {
            if (reader != null)
            {
                reader.Close();
                reader.Dispose();
                conn.Close();
            }

            throw ex;
        }


        return reader;

    }


    public System.Data.DataSet GetDataTable(string sql = null, 
        string    condb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.79)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=ney)));Persist Security Info=True;User ID=platform; Password=intest;Pooling=true;Min Pool Size=1;Connection Lifetime=120;Connection Timeout=60;"
        )
    {

        //初始化联接字符串
        //var condb = "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.79)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=ney)));Persist Security Info=True;User ID=platform; Password=intest;Pooling=true;Min Pool Size=1;Connection Lifetime=120;Connection Timeout=60;";
        string query = string.IsNullOrEmpty(sql) ? "select *  from    Incom_terminal" : sql;

        DataSet MyDs = new DataSet();
        //先查询,如果终端号不存在则添加
        using (OracleConnection conn = new OracleConnection(condb))
        {
            Oracle.DataAccess.Client.OracleDataAdapter MyDa = new OracleDataAdapter(query, conn);
            MyDa.SelectCommand.CommandType = CommandType.Text;
            try
            {
                MyDa.Fill(MyDs);
            }
            catch (OracleException ex)
            {
                throw ex;
            }
            finally
            {
                conn.Close();
            }

        }
        return MyDs;

    }
    #endregion

    #region 动态生成数据实体类,并创建DataReader读取表达式
    /// <summary>
    /// 获取table
    /// </summary>
    public System.Linq.Expressions.LambdaExpression CreateCodes(DataTable tb)
    {
        var cols = tb.Columns.Cast<DataColumn>();

        var colnames = cols.ToDictionary(p => p.ColumnName);//.Select(p=>p.ColumnName)

        var strs = string.Join(",\r\n", colnames.Select(p => p.Key + "  = p[\"" + p.Key + "\"]==DBNull.Value?string.Empty:p[\"" + p.Key + "\"].ToString() "));

        var colsrows = tb.Rows.Cast<DataRow>().Select(p =>
            new
            {
                ColumnName = p["ColumnName"] == DBNull.Value ? string.Empty : p["ColumnName"].ToString(),
                ColumnOrdinal = p["ColumnOrdinal"] == DBNull.Value ? string.Empty : p["ColumnOrdinal"].ToString(),
                ColumnSize = p["ColumnSize"] == DBNull.Value ? string.Empty : p["ColumnSize"].ToString(),
                NumericPrecision = p["NumericPrecision"] == DBNull.Value ? string.Empty : p["NumericPrecision"].ToString(),
                NumericScale = p["NumericScale"] == DBNull.Value ? string.Empty : p["NumericScale"].ToString(),
                IsUnique = p["IsUnique"] == DBNull.Value ? string.Empty : p["IsUnique"].ToString(),
                IsKey = p["IsKey"] == DBNull.Value ? string.Empty : p["IsKey"].ToString(),
                IsRowID = p["IsRowID"] == DBNull.Value ? string.Empty : p["IsRowID"].ToString(),
                BaseColumnName = p["BaseColumnName"] == DBNull.Value ? string.Empty : p["BaseColumnName"].ToString(),
                BaseSchemaName = p["BaseSchemaName"] == DBNull.Value ? string.Empty : p["BaseSchemaName"].ToString(),
                BaseTableName = p["BaseTableName"] == DBNull.Value ? string.Empty : p["BaseTableName"].ToString(),
                DataType = p["DataType"] == DBNull.Value ? string.Empty : p["DataType"].ToString(),
                ProviderType = p["ProviderType"] == DBNull.Value ? string.Empty : p["ProviderType"].ToString(),
                AllowDBNull = p["AllowDBNull"] == DBNull.Value ? false : Boolean.Parse(p["AllowDBNull"].ToString()),
                IsAliased = p["IsAliased"] == DBNull.Value ? string.Empty : p["IsAliased"].ToString(),
                IsByteSemantic = p["IsByteSemantic"] == DBNull.Value ? string.Empty : p["IsByteSemantic"].ToString(),
                IsExpression = p["IsExpression"] == DBNull.Value ? string.Empty : p["IsExpression"].ToString(),
                IsHidden = p["IsHidden"] == DBNull.Value ? string.Empty : p["IsHidden"].ToString(),
                IsReadOnly = p["IsReadOnly"] == DBNull.Value ? string.Empty : p["IsReadOnly"].ToString(),
                IsLong = p["IsLong"] == DBNull.Value ? string.Empty : p["IsLong"].ToString(),
                UdtTypeName = p["UdtTypeName"] == DBNull.Value ? string.Empty : p["UdtTypeName"].ToString()
            });

        var codes = string.Join("\r\n", colsrows.Select(p => string.Format("public {0} {1} {{ get; set; }} ", p.AllowDBNull ? (
          (p.DataType != typeof(string).FullName ? "System.Nullable<" + p.DataType + "> " : p.DataType)
            //""+ p.DataType
                ) : p.DataType, p.ColumnName)));
        var classcode = "public class ABC{\r\n" + codes + "\r\n}";

        //开始动态生成代码
        Tong.CreateNewType.CSharpExe cs = new Tong.CreateNewType.CSharpExe();
        //cs.CompilerCparmae.ReferencedAssemblies.Clear();
        //var refass = this.GetType().Assembly.GetReferencedAssemblies();  
        //var resl= from an in refass  
        // let ass=  System.Reflection.Assembly.Load(an)   select (ass.GlobalAssemblyCache? an.Name + ".dll"  
        //    //引用外部dll "C:\mydll.dll"  
        //    :  "\""+ass.Location +"\"");
        //cs.CompilerCparmae.ReferencedAssemblies.AddRange(resl.ToArray());
        //开始编译
        var asds = cs.RunCode(classcode);

        //创建泛类型实例
        var type = typeof(List<>);
        var entityType = asds.CompiledAssembly.GetType("ABC");
        var dsc = type.MakeGenericType(asds.CompiledAssembly.GetType("ABC"));
        var method = typeof(DataReaderReadExtend).GetMethod("ReaderToList");
        //创建泛类型方法
        method = method.MakeGenericMethod(entityType);

        //System.Linq.Expressions.Expression<Func<IDataReader, List<book>>> exa = (IDataReader n) => n.ReaderToList<book>(true);
        //产生动态表达式树
        var par1 = System.Linq.Expressions.Expression.Parameter(typeof(IDataReader), "r");
        var cons1 = System.Linq.Expressions.Expression.Constant(false);
        var par2 = System.Linq.Expressions.Expression.Parameter(typeof(bool), "t");

        var exme = System.Linq.Expressions.Expression.Call(method, par1, cons1);

        //var expr = System.Linq.Expressions.Expression.Lambda(exme, par1, par2);
        var expr = System.Linq.Expressions.Expression.Lambda(exme, par1);

        return expr;





    }

    #endregion

    #region Nullable 赋值测试表达式生成
    /// <summary>
    /// 设置值类型的Nullable值 赋值 表达式生成器
    /// 包括自动数据实体类生成, 等功能.
    /// </summary>
    /// <returns></returns>
    public Action<T, int> SetNullableValue<T>()
    {
        Type tp = typeof(T);
        Type valType = null;
        System.Reflection.PropertyInfo per = tp.GetProperty("Abc");
        if (IsNullableType(per.PropertyType))
        {
            //获取值类型
            var types = per.PropertyType.GetGenericArguments();
            if (types.Length > 0)
            {
                valType = types[0];
            }
        }

        ParameterExpression e = Expression.Parameter(typeof(T), "e");
        MemberExpression ep = Expression.PropertyOrField(e, "Abc");
        ParameterExpression exp = Expression.Parameter(valType, "n");

        var meth = typeof(accc).GetMethod("ValueAction");
        var genthod = meth.MakeGenericMethod(typeof(int));
        //调用方法生成委托
        Delegate thod = (Delegate)genthod.Invoke(null, null);
        //将委托邦定到表达式树
        MethodCallExpression call = Expression.Call(thod.Method, exp);

        BinaryExpression assignExpression = BlockExpression.Assign(ep, call);

        Expression<Action<T, int>> resultEx = BlockExpression.Lambda<Action<T, int>>(assignExpression, e, exp);

        return resultEx.Compile();

    }
    #endregion



    /// <summary>
    /// 返回null
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="par"></param>
    /// <returns></returns>
    public static Func<T, Nullable<T>> ValueAction<T>() where T : struct
    {
        Func<T, Nullable<T>> fun = val => new Nullable<T>(val);
        return fun;
    }


    #region 填充实体类值

    /// <summary>
    /// nullable类型
    /// </summary>
    private Type nullableType = typeof(Nullable<>);
    /// <summary>
    /// 判断一个类型是否为  Nullable 值类型
    /// </summary>
    /// <param name="theType">值类型数据</param>
    /// <returns>是ull</returns>
    public bool IsNullableType(Type theType)
    {
        return (theType.IsGenericType && theType.
          GetGenericTypeDefinition().Equals
          (nullableType));
    }
    /// <summary>
    /// 获取指定索引的数据并且返回调用委托
    /// </summary>
    /// <typeparam name="T">实体类类型</typeparam>
    /// <typeparam name="T1">结果类型</typeparam>
    /// <param name="index">当前对应在DataReader中的索引</param>
    /// <param name="ProPertyName">对应实体类属性名</param>
    /// <param name="FieldType">字段类型</param>
    /// <returns>返回通过调用的委托</returns>
    public Action<T, IDataRecord> SetValueToEntity<T>(int index, string ProPertyName, Type FieldType)
    {
        Type datareader = typeof(IDataRecord);
        var Mdthods = datareader.GetMethods().Where(p => p.ReturnType == FieldType && p.Name.StartsWith("Get") && p.GetParameters().Where(n => n.ParameterType == typeof(int)).Count() == 1);
        //获取调用方法
        System.Reflection.MethodInfo Method = null;
        if (Mdthods.Count() > 0)
        {
            Method = Mdthods.FirstOrDefault();
        }
        else
        {
            throw new EntryPointNotFoundException("没有从DataReader找到合适的取值方法");
        }
        ParameterExpression e = Expression.Parameter(typeof(T), "e");
        ParameterExpression r = Expression.Parameter(datareader, "r");
        //常数表达式
        ConstantExpression i = Expression.Constant(index);
        MemberExpression ep = Expression.PropertyOrField(e, ProPertyName);
        MethodCallExpression call = Expression.Call(r, Method, i);



        //instance.Property = value 这名话是重点
        BinaryExpression assignExpression = Expression.Assign(ep, call);
        var ex = Expression.Lambda(assignExpression, e, r);

        Expression<Action<T, IDataRecord>> resultEx = Expression.Lambda<Action<T, IDataRecord>>(assignExpression, e, r);
        Action<T, IDataRecord> result = resultEx.Compile();

        return result;
    }

    /// <summary>
    /// 获取指定索引的数据并且返回调用委托,用于处理Nullable值类型值
    /// </summary>
    /// <typeparam name="T">实体类类型</typeparam>
    /// <typeparam name="T1">结果类型</typeparam>
    /// <param name="index">当前对应在DataReader中的索引</param>
    /// <param name="ProPertyName">对应实体类属性名</param>
    /// <param name="FieldType">字段类型</param>
    /// <param name="isNnullable">是否null值</param>
    /// <returns>返回通过调用的委托</returns>
    public Action<T, IDataRecord> SetValueToEntity<T>(int index, string ProPertyName, Type FieldType, bool isNnullable)
    {

        Action<T, IDataRecord> result;
        //不是nullable正常返回
        if (!isNnullable)
        {
            result = SetValueToEntity<T>(index, ProPertyName, FieldType);
        }
        else
        {
            //是 nullable 需要重新计算
            Type datareader = typeof(IDataRecord);
            //获取值类型
            var types = FieldType.GetGenericArguments();
            Type valType = null;
            if (types.Length > 0)
            {
                valType = types[0];
            }
            //这个方法是获取值的功能
            var Mdthods = datareader.GetMethods().Where(p => p.ReturnType == valType && p.Name.StartsWith("Get") && p.GetParameters().Where(n => n.ParameterType == typeof(int)).Count() == 1);
            //获取调用方法
            System.Reflection.MethodInfo Method = null;
            if (Mdthods.Count() > 0)
            {
                Method = Mdthods.FirstOrDefault();
            }
            else
            {
                throw new EntryPointNotFoundException("没有从DataReader找到合适的取值方法");
            }
            //处理表达式
            ParameterExpression e = Expression.Parameter(typeof(T), "e");
            ParameterExpression r = Expression.Parameter(datareader, "r");
            //常数表达式
            ConstantExpression i = Expression.Constant(index);
            MemberExpression ep = Expression.PropertyOrField(e, ProPertyName);
            //调用dataReader的取值方法
            MethodCallExpression call = Expression.Call(r, Method, i);

            #region Nullable
            //Nullable处理
            var meth = typeof(accc).GetMethod("ValueAction");
            var genthod = meth.MakeGenericMethod(valType);
            //调用方法生成委托
            Delegate thod = (Delegate)genthod.Invoke(null, null);
            //将委托邦定到表达式树 new Nullable<int>(121);
            MethodCallExpression callNullable = Expression.Call(thod.Method, call);
            #endregion


            //处理值
            BinaryExpression assignExpression = Expression.Assign(ep, callNullable);
            var ex = Expression.Lambda(assignExpression, e, r);
            Expression<Action<T, IDataRecord>> resultEx = Expression.Lambda<Action<T, IDataRecord>>(assignExpression, e, r);
            result = resultEx.Compile();
        }


        return result;
    }



    /// <summary>
    /// 获取指定索引的数据并且返回调用委托
    /// </summary>
    /// <typeparam name="T">实体类类型</typeparam>
    /// <typeparam name="T1">结果类型</typeparam>
    /// <param name="index">当前对应在DataReader中的索引</param>
    /// <param name="ProPertyName">对应实体类属性名</param>
    /// <param name="canreturn">是否有返回值</param>
    /// <returns>返回通过调用的委托</returns>
    public Func<T, IDataReader, T1> SetValueToEntity<T, T1>(int index, string ProPertyName)
    {
        Type datareader = typeof(IDataRecord);
        var Mdthods = datareader.GetMethods().Where(p => p.ReturnType == typeof(T1));
        //获取调用方法
        System.Reflection.MethodInfo Method = null;
        if (Mdthods.Count() > 0)
        {
            Method = Mdthods.FirstOrDefault();
        }
        else
        {
            throw new EntryPointNotFoundException("没有从DataReader找到合适的取值方法");
        }
        ParameterExpression ent = Expression.Parameter(typeof(T), "e");
        ParameterExpression dr = Expression.Parameter(datareader, "r");
        //常数表达式
        ConstantExpression di = Expression.Constant(index);
        MemberExpression per = Expression.PropertyOrField(ent, ProPertyName);
        MethodCallExpression callmeth = Expression.Call(dr, Method, di);

        //instance.Property = value 这句话是重点
        BinaryExpression assignExpression = Expression.Assign(per, callmeth);
        var ex = Expression.Lambda(assignExpression, ent, dr);

        Expression<Func<T, IDataRecord, T1>> resultEx = Expression.Lambda<Func<T, IDataRecord, T1>>(assignExpression, ent, dr);
        Func<T, IDataRecord, T1> result = resultEx.Compile();

        return result;
    }
    #endregion
}
/// <summary>
/// 测试用实体类
/// </summary>
public class accc
{

    /// <summary>
    /// 一值类型的null属性
    /// </summary>
    public System.Nullable<int> TERMINALCODE { get; set; }
    /// <summary>
    /// 一值类型的null属性
    /// </summary>
    public System.Nullable<int> Abc { get; set; }

    public System.Int64 bb { get; set; }



    /// <summary>
    /// 返回null
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="par"></param>
    /// <returns></returns>
    public static Func<T, Nullable<T>> ValueAction<T>() where T : struct
    {
        Func<T, Nullable<T>> fun = val => new Nullable<T>(val);
        return fun;
    }

}
/// <summary>
/// 故障码实体
/// </summary>
public class Tfault
{
    public System.String FAULTID { get; set; }
    public System.Int32 TERMINALCODE { get; set; }
    public System.String MD5CODE { get; set; }
    public System.String BATCHID { get; set; }
    public System.String FAULTCODE { get; set; }
    public System.DateTime STARTTIME { get; set; }
    public System.Nullable<System.DateTime> ENDTIME { get; set; }
    public System.String NOTE { get; set; }
    public System.Nullable<System.Int16> FLAG { get; set; }
    public System.Nullable<System.DateTime> CREATETIME { get; set; }
    public System.Nullable<System.Double> MAXBUGCODE { get; set; }
    public System.String FAULTCATEGORY { get; set; }
    public System.Nullable<System.Int64> SPN { get; set; }
    public System.Nullable<System.Int64> FMI { get; set; }
    public System.Nullable<System.Int64> SA { get; set; }
    public System.String SUGGESTION { get; set; }
    public System.Nullable<System.Decimal> CARID { get; set; }
}